package org.hyperledger.fabric.example;

import com.google.common.collect.Lists;
import io.netty.util.internal.StringUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.shim.ChaincodeBase;
import org.hyperledger.fabric.shim.ChaincodeStub;
import org.hyperledger.fabric.shim.ResponseUtils;
import org.hyperledger.fabric.shim.ledger.KeyModification;
import org.hyperledger.fabric.shim.ledger.QueryResultsIterator;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 科技资源标识智能合约
 *
 * @author 郭志斌
 * @date 2019/12/24
 */
public class PidChaincode extends ChaincodeBase {

	private static Log _logger = LogFactory.getLog(PidChaincode.class);

	/**
	 * 初始化智能合约
	 *
	 * @param stub
	 * @return Response
	 */
	@Override
	public Response init(ChaincodeStub stub) {
		_logger.info("Init java simple chaincode");
		return ResponseUtils.newSuccessResponse();
	}

	/**
	 * 调用 Chaincode method
	 *
	 * @param stub ChaincodeStub
	 * @return Response
	 */
	@Override
	public Response invoke(ChaincodeStub stub) {
		try {
			_logger.info("Invoke java simple chaincode");
			String func = stub.getFunction();
			List<String> params = stub.getParameters();
			//通过 function name 调用 Chaincode 上的对应方法
			if (func.equals("invoke")) {
				return invoke(stub, params);
			}
			if (func.equals("delete")) {
				return delete(stub, params);
			}
			if (func.equals("query")) {
				return query(stub, params);
			}
			if (func.equals("queryHistory")) {
				return queryHistory(stub, params);
			}
			return ResponseUtils.newErrorResponse("Invalid invoke function name. Expecting one of: [\"invoke\"," +
					"\"delete\",\"queryHistory\", \"query\"]");
		} catch (Throwable e) {
			return ResponseUtils.newErrorResponse(e);
		}
	}

	/**
	 * 新增 & 修改状态数据,使用 couchdb 存储
	 *
	 * @param stub ChaincodeStub
	 * @param args 请求参数
	 * @return Response
	 */
	private Response invoke(ChaincodeStub stub, List<String> args) {
		if (args.size() != 4) {
			return ResponseUtils.newErrorResponse("Incorrect number of arguments. Expecting 2");
		}
		//cstr
		String key = args.get(0);

		_logger.info(String.format("key is : %s", key));

		//事务ID
		String txId = stub.getTxId();
		_logger.info(String.format("txId is : %s", txId));

		Map<String,String> param = new HashMap<>(5);
		param.put("pid",args.get(1));
		param.put("url",args.get(2));
		param.put("org",args.get(3));
		param.put("timestamp",System.currentTimeMillis() + "");
		param.put("txId",txId);

		String val = new JSONObject(param).toString();
		_logger.info(String.format("value is : %s", val));

		//存储状态数据 key-value
		stub.putState(key, val.getBytes());

		_logger.info("Transfer complete");

		return ResponseUtils.newSuccessResponse("invoke finished successfully");
	}

	/**
	 * 删除状态数据
	 *
	 * @param stub ChaincodeStub
	 * @param args 请求参数
	 * @return Response
	 */
	private Response delete(ChaincodeStub stub, List<String> args) {
		if (args.size() != 1) {
			return ResponseUtils.newErrorResponse("Incorrect number of arguments. Expecting 1");
		}
		String key = args.get(0);
		// Delete the key from the state in ledger
		_logger.info("delete key is : " + key);
		//删除账本信息
		stub.delState(key);
		return ResponseUtils.newSuccessResponse();
	}

	/**
	 * 查询状态数据
	 *
	 * @param stub ChaincodeStub
	 * @param args 请求参数
	 * @return Response
	 */
	private Response query(ChaincodeStub stub, List<String> args) {
		if (args.size() != 1) {
			return ResponseUtils.newErrorResponse("Incorrect number of arguments. Expecting name of the person to " +
					"query");
		}
		String key = args.get(0);
		//byte[] stateBytes
		byte[] val	= stub.getState(key);

		if (val == null) {
			//String ret = new String((val),java.nio.charset.StandardCharsets.UTF_8);
			return ResponseUtils.newErrorResponse(String.format("Error: state for %s is null", key));
		}
		_logger.info(String.format("Query Response key is : %s, value is : %s", key, val));
		return ResponseUtils.newSuccessResponse(val);
	}

	/**
	 * 查询历史数据
	 *
	 * @param stub ChaincodeStub
	 * @param args 请求参数
	 * @return Response
	 */
	private Response queryHistory(ChaincodeStub stub, List<String> args) {
		if (args.size() != 1) {
			return ResponseUtils.newErrorResponse("Incorrect number of arguments. Expecting name of the person to " +
					"queryHistory");
		}
		String key = args.get(0);
		//byte[] stateBytes
		QueryResultsIterator<KeyModification> historyForKey = stub.getHistoryForKey(key);
		_logger.info(String.format("Query Response historyForKey is : %s", historyForKey));

		if(!historyForKey.iterator().hasNext()){
			return ResponseUtils.newErrorResponse(String.format("Error: history for %s is null", key));
		}

		List<String> historyList = Lists.newArrayList();
		for (KeyModification keyModification : historyForKey) {
			if (StringUtil.isNullOrEmpty(keyModification.getStringValue())){
				continue;
			}
			historyList.add(keyModification.getStringValue());
			_logger.info(String.format("history value is : %s", keyModification.getStringValue()));
		}

		String ret = new JSONObject().put("key",key).put("data",historyList).toString();

		_logger.info(String.format("Query Response key is : %s, history value is : %s", key, ret));
		return ResponseUtils.newSuccessResponse(ret);
	}

	/**
	 * chaincode main
	 *
	 * @param args
	 */
	public static void main(String[] args) {
		new PidChaincode().start(args);
	}
}
